package com.qf.base.util;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author 汤奇
 * @version V1.0
 * @Project BookPro
 * @Package com.qf.base.util
 * @Description: 非对称加密RSA算法的工具类
 * @Date 2022/8/7 21:56
 */
public class RsaUtil {
    /**
     * 私钥
     */
    public static String privateKeyString;

    /**
     * 公钥
     */
    public static String publicKeyString;

    /**
     * 生成随机的密钥对(公钥, 私钥)
     */
    public static void genKeyPair(){
        try {
            //生成RSA密钥对的生成器
            KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
            //初始化密钥对生成器
            rsa.initialize(1024,new SecureRandom());
            //生成一个密钥对
            KeyPair keyPair = rsa.generateKeyPair();
            //获取公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            //获取私钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            //以base64的形式存储公钥和私钥
            publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
            privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()));

        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 公钥加密
     * @param str               待加密的字符串
     * @param publicKey   加密使用的公钥
     * @return                      加密之后的密文
     */
    public static String encryptPub(String str, String publicKey){
        try {
            //把公钥由base64还原为字节数组
            byte[] bytes = Base64.decodeBase64(publicKey);
            //把公钥由字节数组, 还原为公钥对象
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bytes));
            //计算加密对象
            Cipher cipher = Cipher.getInstance("RSA");
            //指定 计算模式为加密, 使用的密钥
            cipher.init(Cipher.ENCRYPT_MODE,pubKey);
            //做加密这件事
            String result = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
            return result;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥解密
     * @param str               待解密的字符串
     * @param privateKey  解密使用的私钥
     * @return                      解密之后的原文
     */
    public static String decryptPri(String str, String privateKey){
        try {
            //把base64的私钥还原
            byte[] bytes = Base64.decodeBase64(privateKey);
            //计算出待解密字符换的字节数组
            byte [] inputByte=Base64.decodeBase64(str.getBytes("UTF-8"));
            //把私钥对象还原
            RSAPrivateKey priKey= (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(bytes));
            //获取解密的对象
            Cipher cipher=Cipher.getInstance("RSA");
            //设置计算模式为解密，指定私钥
            cipher.init(Cipher.DECRYPT_MODE,priKey);
            //进行解密
            String result=new String(cipher.doFinal(inputByte));
            return result;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    public static String encryptPri(String str, String privateKey){
        try {
            //把私钥由base64还原为字节数组
            byte[] bytes = Base64.decodeBase64(privateKey);
            //把私钥由字节数组还原为私钥对象
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(bytes));
            //用于计算的对象
            Cipher cipher = Cipher.getInstance("RSA");
            //指定计算模式为加密, 使用的钥匙为私钥
            cipher.init(Cipher.ENCRYPT_MODE,priKey);
            //进行加密
            String result = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥解密
     * @param str               待解密的密文
     * @param publicKey   解密时使用的公钥
     * @return                      解密之后的原文
     */
    public static String decryptPub(String str, String publicKey){
        try {
            //拿到密文对应的字节数组
            byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
            //把公钥还原成字节数组
            byte[] keyByte = Base64.decodeBase64(publicKey);
            //把公钥还原成对象
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyByte));
            //Rsa解密
            Cipher cipher = Cipher.getInstance("RSA");
            //指定计算方式为解密, 指定密钥为公钥
            cipher.init(Cipher.DECRYPT_MODE,pubKey);
            //进行解密
            String result = new String(cipher.doFinal(inputByte));
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
